package com.xk.aspect;

import com.alibaba.fastjson.JSON;
import com.xk.annotation.SystemLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 日志切面类
 */
@Aspect
@Component
@Slf4j
public class LogAapect {
    /**
     * 切点
     */
    @Pointcut("@annotation(com.xk.annotation.SystemLog)")
    public void pt(){
    }

    /**
     * 打印日志的 环绕通知
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("pt()")
    public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable {

        Object result=null;
        try {
            //打印执行方法前的日志
            handleBefore(joinPoint);
            result = joinPoint.proceed();
            //打印执行方法后的日志
            handlAfter(result);
        } finally {
            // 结束后换行
            log.info("=======End=======" + System.lineSeparator());
        }
        return result;
    }
    /**
     * 切入点执行结束 会执行 的打印日志方法
     * @param result 目标方法执行结果
     */
    private void handlAfter(Object result) {
        // 打印出参
        log.info("Response       : {}",  JSON.toJSONString(result));
    }

    /**
     * 切入点执行之前 会执行 的打印日志方法
     */
    private void handleBefore(ProceedingJoinPoint joinPoint) {

        //当前绑定到线程的请求属性 ,获取request对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //获取请求,可以获取到URL
        String url = String.valueOf(request.getRequestURL());

        //获取被增强方法上的注解对象
        SystemLog systemLog = getSystemLog(joinPoint);

        log.info("=======Start=======");
        // 打印请求 URL
        log.info("URL            : {}", url);
        // 打印描述信息
        log.info("BusinessName   : {}",  systemLog.businessName());
        // 打印 Http method
        log.info("HTTP Method    : {}",  request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringType().getTypeName(),((MethodSignature) joinPoint.getSignature()).getName());
        // 打印请求的 IP
        log.info("IP             : {}", request.getRemoteHost());
        // 打印请求入参
        log.info("Request Args   : {}", JSON.toJSONString(joinPoint.getArgs()));
    }

    /**
     * 获取切入点(目标方法) 的SystemLog注解对象
     * @param joinPoint 代理对象的信息
     * @return SystemLog注解对象
     */
    private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = ((MethodSignature) joinPoint.getSignature());
        return signature.getMethod().getAnnotation(SystemLog.class);
    }
}
